2

Circlr是一款可以对产品图片进行360度全方位旋转展示的插件。Circlr通过按一定角度规律拍摄的产品图片,制作出可以使用鼠标拖动、鼠标滚轮和移动触摸来进行图片逐帧旋转的效果。比先前的Rollerblade,动画顺畅了许多,也更易于控制,该插件非常适合于商品的展示。它的特点有:
1、支持水平或垂直方向旋转。
2、支持移动触摸事件。
3、支持滚动事件。
4、图片预加载处理。
5、可以反向和循环旋转图片。

页面引用核心jquery.js和circlr.js文件
<script scr="js/circlr.js"></script>
<script scr="js/jquery.js"></script>
对于circlr.js可以去自行下载
原文件展示给大家,以供预览:

// Circlr © 2014-2015 Andrey Polischuk
// github.com/andrepolischuk/circlr

!function() {

  'use strict';

  /**
   * Mutable parameters
   */

  var mutable = [
    'vertical',
    'reverse',
    'cycle',
    'speed',
    'playSpeed'
  ];

  /**
   * Initialize module
   * @param {Object} el
   * @param {Object} options
   */

  function Circlr(options) {

    /**
     * Mouse events enabled
     */

    options.mouse = options.mouse || true;

    /**
     * Scroll events enabled
     */

    options.scroll = options.scroll || false;

    /**
     * Orientation
     */

    options.vertical = options.vertical || false;

    /**
     * Turning reverse
     */

    options.reverse = options.reverse || false;

    /**
     * Turning cycle
     */

    options.cycle = options.cycle || true;

    /**
     * Start frame
     */

    options.start = options.start || 0;

    /**
     * Turn speed (ms)
     */

    options.speed = options.speed || 50;

    /**
     * Autoplay
     */

    var autoplay = options.autoplay || false;

    /**
     * Play speed (ms)
     */

    options.playSpeed = options.playSpeed || 100;

    /**
     * DOM element
     */

    var el = this.el = options.element;

    /**
     * Exclude duplication
     */

    el.setAttribute('data-circlr', true);

    /**
     * DOM loader
     */

    var loader = options.loader ? document.getElementById(options.loader) : undefined;

    /**
     * Frames length
     */

    var length = this.length = el.getElementsByTagName('img').length;

    /**
     * Frames area height
     */

    var height = options.height || undefined;

    /**
     * Frames area width
     */

    var width = options.width || undefined;

    /**
     * Move enable
     */

    var movable = false;

    /**
     * Loaded images length
     */

    var loaded = [];

    /**
     * Not loaded length
     */

    var errored = [];

    /**
     * Current frame
     */

    var current;

    /**
     * Prevous options
     */

    var pre   = {};

    pre.Y     = null;
    pre.X     = null;
    pre.frame = 0;

    /**
     * Callbacks
     */

    var callbacks = {};

    // all images loaded callback
    callbacks.ready = options.ready || undefined;

    // turn callback
    callbacks.change = options.change || undefined;

    /**
     * Scroll events
     */

    var scrollEvents = [
      'wheel',
      'mousewheel',
      'scroll',
      'DOMMouseScroll'
    ];

    /**
     * Add event listener
     * @param {Object} target
     * @param {String} event
     * @param {Function} fn
     * @api private
     */

    function onEventListener(target, event, fn) {

      if (target.addEventListener) {
        target.addEventListener(event, fn, false);
      } else {
        target.attachEvent('on' + event, function() {
          fn.call(target, window.event);
        });
      }

    }

    /**
     * Prevent default
     * @param {Object} e
     */

    function preventDefault(e) {

      if (e.preventDefault) {
        e.preventDefault();
      } else {
        e.returnValue = false;
      }

    }

    /**
     * Pre moving event
     * @param {Object} e
     * @api private
     */

    function preMove(e) {

      autoplay = false;

      preventDefault(e);
      e = e.type === 'touchstart' ? e.changedTouches[0] : e;

      movable = true;

      if (options.vertical) {
        pre.Y = e.clientY - el.offsetTop;
      } else {
        pre.X = e.clientX - el.offsetLeft;
      }

    }

    /**
     * Normalize current frame
     * @param  {Number} cur
     * @return {Number}
     * @api private
     */

    function normalize(cur) {

      if (cur < 0) {
        cur = options.cycle ? cur + length : 0;
      } else if (cur > length - 1) {
        cur = options.cycle ? cur - length : length - 1;
      }

      return cur;

    }

    /**
     * Moving event
     * @param {Object} e
     * @api private
     */

    function isMove(e) {

      if (movable) {

        preventDefault(e);
        e = e.type === 'touchmove' ? e.changedTouches[0] : e;

        // current offset (px)
        var offset = (options.vertical) ? ((e.clientY - el.offsetTop) - pre.Y) : ((e.clientX - el.offsetLeft) - pre.X);
        offset = options.reverse ? -offset : offset;

        // frame step (px)
        var step = width / length;

        // prevous frame
        var previous = current;

        // current offset (frame)
        offset = Math.floor(offset / step);

        if (offset !== current) {

          current = normalize(pre.frame + offset);

          if (previous !== current) {

            // show current frame
            el.getElementsByTagName('img')[previous].style.display = 'none';
            el.getElementsByTagName('img')[current].style.display = 'block';

            if (typeof callbacks.change === 'function') {
              callbacks.change(current, length);
            }

          }

        }

      }

    }

    /**
     * Post moving event
     * @param {Object} e
     * @api private
     */

    function stopMove(e) {

      preventDefault(e);

      movable   = false;
      pre.frame = current;

    }

    /**
     * Moving via scroll
     * @param {Object} e
     * @api private
     */

    function scrollMove(e) {

      autoplay = false;

      preventDefault(e);

      // scroll delta
      var delta = e.deltaY || e.detail || (-e.wheelDelta);
      delta = delta / Math.abs(delta);
      delta = options.reverse ? -delta : delta;

      current = normalize(current + delta);

      // show current frame
      el.getElementsByTagName('img')[pre.frame].style.display = 'none';
      el.getElementsByTagName('img')[current].style.display = 'block';

      pre.frame = current;

      if (typeof callbacks.change === 'function') {
        callbacks.change(current, length);
      }

    }

    /**
     * Initialize events after success images loading
     * @api private
     */

    function initEvents() {

      // loader hide
      if (loader) {
        loader.style.display = 'none';
      }

      if (errored.length === 0) {

        var start = normalize(options.start);

        // all images loaded
        el.getElementsByTagName('img')[start].style.display = 'block';
        current = start;

        el.style.position   = 'relative';
        el.style.width      = '100%';

        if ('ontouchstart' in window || 'onmsgesturechange' in window) {

            if (options.mouse || options.scroll) {
              onEventListener(el, 'touchstart', preMove);
              onEventListener(el, 'touchmove', isMove);
              onEventListener(el, 'touchend', stopMove);
            }

        } else {

          if (options.mouse) {
            onEventListener(el, 'mousedown', preMove);
            onEventListener(el, 'mousemove', isMove);
            onEventListener(document, 'mouseup', stopMove);
          }

          if (options.scroll) {
            for (var e = 0; e < scrollEvents.length; e++) {
              if ('on' + scrollEvents[e] in window) {
                onEventListener(el, scrollEvents[e], scrollMove);
                break;
              }
            }
          }

        }

        if (autoplay) {
          play();
        }

      }

      if (typeof callbacks.ready === 'function') {
        callbacks.ready(errored);
      }

    }

    /**
     * Initialize images events
     * @param {Object} img
     */

    function loadImagesEvents(img) {

      img.onload = function() {

        loaded.push(this.src);

        // show first frame when all images loaded
        if (loaded.length + errored.length === length) {
          initEvents();
        }

      };

      img.onerror = function() {

        errored.push(this.src);

        // show first frame when images loaded
        if (loaded.length + errored.length === length) {
          initEvents();
        }

      };

      img.onreadystatechange = function() {
        this.onload();
      };

    }

    /**
     * Load Object images
     * @api private
     */

    function loadImages() {

      // adding elements
      var img;

      // show loader
      if (loader) {
        loader.style.display = 'block';
      }

      for (var i = 0; i < length; i++) {

        // get object
        img = el.getElementsByTagName('img')[i];

        // set object style
        img.style.display      = 'none';
        img.style.width        = '100%';

        // set object options
        img.setAttribute('src', img.getAttribute('data-src'));
        img.setAttribute('data-index', i);
        img.removeAttribute('data-src');

        loadImagesEvents(img);

      }

      // check elements sizes
      height = height || el.clientHeight;
      width  = width || el.clientWidth;

    }

    /**
     * Initialize loading
     */

    loadImages();

    /**
     * Change current frame
     * @param  {Number} i
     * @api private
     */

    function setFrame(i) {

      el.getElementsByTagName('img')[current].style.display = 'none';
      el.getElementsByTagName('img')[i].style.display = 'block';

      pre.frame = current = i;

    }

    /**
     * Turn to specific frame
     * @param  {Number} i
     * @api public
     */

    var turn = this.turn = function(i) {

      i = normalize(i);
      autoplay = true;

      (function turnInterval() {

        if (i !== current && autoplay) {

          setFrame(normalize(i < current ? current - 1 : current + 1));
          setTimeout(turnInterval, typeof i === 'undefined' ? options.playSpeed : options.speed);

        } else if (i === current) {

          pre.frame = current = i;
          autoplay = false;

          if (typeof callbacks.change === 'function') {
            callbacks.change(current, length);
          }

        }

      })();

    };

    /**
     * Go to specific frame
     * @param  {Number} i
     * @api public
     */

    this.go = function(i) {

      if (i !== current) {

        setFrame(i);

        if (typeof callbacks.change === 'function') {
          callbacks.change(current, length);
        }

      }

    };

    /**
     * Play sequence
     * @api public
     */

    var play = this.play = function() {
      autoplay = true;
      turn();
    };

    /**
     * Stop sequence playng
     * @api public
     */

    this.stop = function() {
      autoplay = false;
    };

    /**
     * Show object
     * @api public
     */

    this.show = function() {
      el.style.display = 'block';
    };

    /**
     * Hide object
     * @api public
     */

    this.hide = function() {
      el.style.display = 'none';
    };

    /**
     * Change Object options
     * @param {Object} options
     * @api public
     */

    this.set = function(set) {
      for (var i = 0, key; i < mutable.length; i++) {
        key = mutable[i];
        options[key] = typeof set[key] !== 'undefined' ? set[key] : options[key];
      }
    };

  }

  /**
   * Example creator
   */

  function Creator(element, options) {

    element = document.getElementById(element);

    if (element.getAttribute('data-circlr')) {
      return;
    }

    options = options || {};
    options.element = element;

    return new Circlr(options);

  }

  /**
   * Module exports
   */

  if (typeof define === 'function' && define.amd) {

    define([], function() {
      return Creator;
    });

  } else if (typeof module !== 'undefined' && module.exports) {

    module.exports = Creator;

  } else {

    this.circlr = Creator;

  }

}.call(this);

circle插件的运用很简单:
var crl = circlr(element, options);
// element:放置图片的容器元素的ID。
// options:参数对象。
配置参数
mouse:是否通过鼠标进行图片旋转,默认值为true。
scroll:是否通过scroll进行图片旋转,默认值为false。
vertical:是否在垂直方向上移动鼠标时旋转图片,默认值为false。
reverse:是否反转方向,默认值为false。
cycle:是否循环旋转图片,默认值为true。
start:开始动画帧,默认值为0。
speed:动画帧通过circlr.turn(i)切换的速度,默认值为50毫秒。
autoplay:是否自动进行图片360度旋转播放,默认值为false。
playSpeed:动画序列的播放速度,默认值为100毫秒。
loader:预加载DOM元素的ID。
ready:图片加载完成后的回调函数。
change:动画帧改编之后的回调函数(以当前帧和总帧数为参数)。
方法
crl.el:返回对象的DOM元素节点。
crl.length:返回对象的总的动画帧数。
crl.turn(i):动画旋转到第i帧。
crl.go(i):动画跳转到第i帧。
crl.play():开始动画序列的播放。
crl.stop():停止动画播放。
crl.hide():隐藏对象的DOM元素节点。
crl.show():显示对象的DOM元素节点。
crl.set(options):在插件初始化之后改变对象的参数:vertical 、reverse、cycle、speed、playSpeed
浏览器兼容
Internet Explorer 7+
Chrome
Safari
Firefox
Opera
以下基于circle的插件
<script src="js/circlr-config.js"></script>
circlr-config.js的源码

/*
 *     @author: 21-sun
 *     @version 1.0.0
 *     @date 2017-05-10
*/
;
(function($){
    
    var defaults = {
        ID : '',
        filePath : '',  // 小图路径:本地
        imgFormat : '.png',  // 图片格式
        len : 50, // 张数配置
        scroll: true, //滚动发滚轮自动旋转
        playSpeed : 400,  // 播放速度
        autoplay : true, // 是否自动播放
        delay : 3 // 不操作后开始自传
        };
    
    $.fn.show360 = function(options, undefined){
        
        var opts = $.extend({}, defaults, options, undefined);
        
        obj = $(this);
        
        var timer = null;
        var isLoaded = false; //判断图片是否加载完成
        var crl = null;
        
        var show = {
            init : function (){
                this.create();
                this.crlFn();
                
                if(opts.autoplay){
                    this.play();
                    this.stop();
                    }
                },
            create : function (){
                var html = '';
                html += '<div id=\"circlr-' + opts.ID + '\" class=\"img-wrap\" style=\"cursor:move;\"><\/div>';
                html += '<div class=\"rotate-tip\"><\/div>';
                html += '<div id=\"loading-' + opts.ID + '\" style=\"position:absolute; left:0; top:0; width:100%; height:100%; background-color:rgba(0,0,0,0.8);\">';
                html += '<div id=\"effect_4\">';
                html += '<div class=\"loading-center\">';
                html += '<div class=\"loading-center-absolute\">';
                html += '<div class=\"object object_one\"><\/div>';
                html += '<div class=\"object object_two\"><\/div>';
                html += '<div class=\"object object_three\"><\/div>';
                html += '<div class=\"object object_four\"><\/div>';
                html += '<\/div>';
                html += '<\/div>';
                html += '<\/div>';
                html += '<\/div>';
                
                obj.html(html);
                
                var step = 0;
                var imgList = '';
                
                for(var i = 0; i < opts.len; i ++){
                    imgList += '<img data-src=\"' + opts.filePath + 'pro_' + i + opts.imgFormat + '\" \/>';
                    }
                
                $('.img-wrap').html(imgList);
                },
            crlFn : function(){
                crl = circlr('circlr-' + opts.ID, {
                    scroll: opts.scroll,
                    loader: 'loading-' + opts.ID,
                    autoplay : opts.autoplay,
                    playSpeed: opts.playSpeed
                    });
                },
            play : function(){
                $('#circlr-' + opts.ID).on('touchend || mouseup', function() {
                    timer = setTimeout(function (){
                        crl.play();
                        }, opts.delay * 1000);
                    });
                },
            stop : function(){
                $('#circlr-' + opts.ID).on('touchstart || mousedown', function() {
                    if(timer !== null){
                        clearTimeout(timer);
                        timer = null;
                        }
                    crl.stop();
                    });
                }
            };
        
        return show.init();
        };
    })(jQuery);

html页面就更简单了:

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>test</title>
<link href="static/ui/ui.css" rel="stylesheet">
<link href="style/style.css" rel="stylesheet">
<link href="static/lib/proSHow/show.css" rel="stylesheet">
</head>

<body>

<div class="test"></div>

<script src="js/jquery-1.7.min.js"></script>
<script src="js/circlr.js"></script>
<script src="js/config-config.js"></script>
<script>
$('.test').show360({
    ID : 'fileName',
    filePath : 'images/fileName/',  //小图路径:本地
    imgFormat : '.png',  //图片格式
    len : 27, //张数配置
    scroll: true, //滚动发滚轮自动旋转
    playSpeed : 400,  // 播放速度
    autoplay : false, //是否自动播放
    delay : 3 //不操作后开始自传
    });
</script>
</body>
</html>

页面中引入show.css
源码:

#effect_4{
    height: 100%;
    width: 100%;
}
#effect_4 .loading-center{
    width: 100%;
    height: 100%;
    position: relative;
}
#effect_4 .loading-center-absolute {
    position: absolute;
    left: 50%;
    top: 50%;
    height: 50px;
    width: 50px;
    margin-top: -25px;
    margin-left: -25px;
   -ms-transform: rotate(45deg); 
       -webkit-transform: rotate(45deg);
    transform: rotate(45deg); 
    -webkit-animation: loading-center-absolute 1.5s infinite;
    animation: loading-center-absolute 1.5s infinite;

}
#effect_4 .object{
    width: 25px;
    height: 25px;
    background-color: #FFF;
    float: left;
    
}

#effect_4 .object_one {
    -webkit-animation: object_one_4 1.5s infinite;
    animation: object_one_4 1.5s infinite;
    }
#effect_4 .object_two {
    -webkit-animation: object_two_4 1.5s infinite;
    animation: object_two_4 1.5s infinite;
    }
#effect_4 .object_three {
    -webkit-animation: object_three_4 1.5s infinite;
    animation: object_three_4 1.5s infinite;
    }
#effect_4 .object_four {
    -webkit-animation: object_four_4 1.5s infinite;
    animation: object_four_4 1.5s infinite;
    }

@-webkit-keyframes loading-center-absolute {
  100% { -webkit-transform: rotate(-45deg); }

}

@keyframes loading-center-absolute {
  100% { 
    transform:  rotate(-45deg);
    -webkit-transform:  rotate(-45deg);
  }
}

@-webkit-keyframes object_one_4 {
  25% { -webkit-transform: translate(0,-50px) rotate(-180deg); }
  100% { -webkit-transform: translate(0,0) rotate(-180deg); }

}

@keyframes object_one_4 {
  25% { 
    transform: translate(0,-50px) rotate(-180deg);
    -webkit-transform: translate(0,-50px) rotate(-180deg);
  } 
  100% { 
    transform: translate(0,0) rotate(-180deg);
    -webkit-transform: translate(0,0) rotate(-180deg);
  }
}

@-webkit-keyframes object_two_4 {
  25% { -webkit-transform: translate(50px,0) rotate(-180deg); }
  100% { -webkit-transform: translate(0,0) rotate(-180deg); }
}

@keyframes object_two_4 {
  25% { 
    transform: translate(50px,0) rotate(-180deg);
    -webkit-transform: translate(50px,0) rotate(-180deg);
  } 
  100% { 
    transform: translate(0,0) rotate(-180deg);
    -webkit-transform: translate(0,0) rotate(-180deg);
  }
}

@-webkit-keyframes object_three_4 {
  25% { -webkit-transform: translate(-50px,0) rotate(-180deg); }
  100% { -webkit-transform: translate(0,0) rotate(-180deg); }
}

@keyframes object_three_4 {
  25% { 
    transform:  translate(-50px,0) rotate(-180deg);
    -webkit-transform:  translate(-50px,0) rotate(-180deg);
  } 
  100% { 
    transform: translate(0,0) rotate(-180deg);
    -webkit-transform: rtranslate(0,0) rotate(-180deg);
  }
}

@-webkit-keyframes object_four_4 {
  25% { -webkit-transform: translate(0,50px) rotate(-180deg); }
  100% { -webkit-transform: translate(0,0) rotate(-180deg); }
}

@keyframes object_four_4 {
  25% { 
    transform: translate(0,50px) rotate(-180deg); 
    -webkit-transform: translate(0,50px) rotate(-180deg);  
  } 
  100% { 
    transform: translate(0,0) rotate(-180deg);
    -webkit-transform: translate(0,0) rotate(-180deg);
  }
}

这样就ok了,有兴趣,可以尝试一下奥。
如果文章有问题,请大家积极指正,共同进步。


sourcenode
307 声望29 粉丝

以少聚多,持之以恒!